<?php if (!defined('CORE_DIR')) die('Wrong entry point!');

/* 
 * Copyright 2010 Anton Muraviev a.k.a kuromaisu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

Aero::define('PipelineSpecification', AS_SINGLETON);

/*
 * PipelineSpecification
 */
class PipelineSpecification extends AeroSpec
{
	protected function itShouldAcceptAStringOrAnArrayAsInput()
	{
		// Use a string first
		$string = 'something|else|parametrized[1,2,"pipe, tube, lube"]';
		$pipeline = Aero::load('libs/pipeline',$string);
		
		$array = $pipeline->toArray();
		
		$this->variable($array)->equals(array(
			array('something'),
			array('else'),
			array('parametrized',1,2,'pipe, tube, lube')
		));
		
		// Try doing the reverse, i.e. pass an array and cast it into string.
		$pipeline2 = Aero::load('libs/pipeline');
		$pipeline2->set($array);
		$this->string($string)->equals($pipeline2->toString());
		
		// Now let's try a slightly invalid array format
		$array2 = array(
			'something',
			array('else'),
			array('parametrized',1,2,'pipe, tube, lube')
		);
		
		$pipeline3 = Aero::load('libs/pipeline',$array2);
		$this->string($string)->equals($pipeline3->toString());
	}
	
	protected function itShouldAllowSegmentManipulation()
	{
		$string = 'something[1,2]|other[fuck]|or|else[kill]';
		$pipeline = Aero::load('libs/pipeline', $string);
		
		$this->value('something[1,2]|other[fuck]|or|else[kill]')->equals($pipeline->toString());
		
		// Appending / prepending segments
		$pipeline->append('bunny[bucks]');
		$pipeline->prepend('micky[mouse]');
		$this->value('micky[mouse]|something[1,2]|other[fuck]|or|else[kill]|bunny[bucks]')
			->equals($pipeline->toString());
		
		// Adding new segments
		$pipeline->add('bunny[dollar]',-6);
		$pipeline->add('minny[mouse]',1);
		$this->value('micky[mouse]|minny[mouse]|bunny[dollar]|something[1,2]|other[fuck]|or|else[kill]|bunny[bucks]')
			->equals($pipeline->toString());
		
		// Deleting segments by name
		$pipeline->delete('bunny');
		$this->value('micky[mouse]|minny[mouse]|'.$string)
			->equals($pipeline->toString());
		
		// Check what segments are present
		$this->isTrue($pipeline->has('micky'));
		$this->isFalse($pipeline->has('bunny'));
	}
	
	protected function itShouldBeAbleToModifyAValueUsingPipelineAsSeriesOfFunctionCalls()
	{
		$pipeline = Aero::load('libs/pipeline','str_replace[1337,"Leet",?]|strtoupper|substr[0,4]');
		
		// Use global context, e.g. regular PHP functions
		$pipeline->setContext(null);
		$result = $pipeline->modify('1337_stRing');
		$this->value($result)->equals('LEET');
		
		// Try an array
		$result = $pipeline->modify(array('1337_stRing','roxxy'));
		$this->value($result)->equals(array('LEET','ROXX'));
	}
	
	public function itShouldBeAbleToRunAValueThroughPipelineAndTestSegmentOutputsAgainstAnotherValueOrUsingACallback()
	{
		$pipeline = Aero::load('libs/pipeline','is_scalar|is_numeric|is_int');
		$pipeline->setContext(null);
		
		// A pipeline, a value and expected segment output
		$this->isTrue($pipeline->test(123, true));
		
		// The following two should fail, because only `integers` would pass.
		$this->value($pipeline->test('123', true))->equals(array('is_int','123'));
		$this->value($pipeline->test(null, true))->equals(array('is_scalar',null));
		
		// Try an array now
		$this->value($pipeline->test(array(123,252,6),true))->equals(array(true,true,true));
		$this->value($pipeline->test(array(123,'252',6),true))->equals(array(true,array('is_int','252'),true));
		
		// This should never fail because all segments would always return either `true` or `false`
		$this->value($pipeline->test(array('123',252,null),'is_bool'))->equals(array(true,true,true));
		
		// This test however should always fail, because none of the segment return a string.
		$this->value($pipeline->test('123','is_string'))->equals(array('is_scalar','123'));
	}
	
	protected function itShouldBeAbleToUseObjectsAndClassesAsSegmentContexts()
	{
		$pipeline = Aero::load('libs/pipeline','test_object_method|test_static_function|is_string');
		
		$pipeline->setContext(array($this, null));
		$this->value($pipeline->test(123,true))->is('true');
	}
	
	public static function testStaticFunction()
	{
		return true;
	}
	
	public function testObjectMethod()
	{
		return self::testStaticFunction();
	}
	
	public function is_string()
	{
		return $this->testObjectMethod();
	}
}